package com.share.finance.fund.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.share.common.common.Page;
import com.share.common.utils.BankCardUtil;
import com.share.common.utils.DateUtil;
import com.share.common.utils.RandomUtil;
import com.share.common.utils.RateUtil;
import com.share.finance.fund.mapper.LoanInfoMapper;
import com.share.finance.fund.mapper.RepaymentPlanMapper;
import com.share.finance.fund.model.db.LoanInfo;
import com.share.finance.fund.model.db.RepaymentPlan;
import com.share.finance.fund.model.db.RepaymentRecord;
import com.share.finance.fund.model.vo.LoanApplyReq;
import com.share.finance.fund.model.vo.LoanRecordPageReq;
import com.share.finance.fund.service.ILoanInfoService;
import com.share.finance.fund.service.IRepaymentPlanService;
import com.share.finance.fund.service.IRepaymentRecordService;
import com.share.finance.risk.common.enums.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 放款记录表  服务实现类
 * </p>
 *
 * @author author
 * @since 2024-08-21
 */
@Slf4j
@Service
public class LoanInfoServiceImpl extends ServiceImpl<LoanInfoMapper, LoanInfo> implements ILoanInfoService {
    @Autowired
    private IRepaymentPlanService repaymentPlanService;

    @Autowired
    private IRepaymentRecordService iRepaymentRecordService;

    @Resource
    private LoanInfoMapper loanInfoMapper;

    @Resource
    private RepaymentPlanMapper repaymentRlanMapper;

    @Override
    public Integer apply(LoanApplyReq req) {
        LoanInfo record = new LoanInfo();
        record.setSessionId(req.getSessionId());
        record.setProductCode(req.getProductCode());
        record.setLoanAmount(req.getLoanAmount());
        record.setBankCard(req.getBankCard());
        record.setName(req.getName());
        record.setPhoneNo(req.getPhoneNo());
        record.setUserId(req.getUserId());
        record.setIdCard(req.getIdCard());
        record.setRepayMethod(RepayMethodEnum.randomValue());
        int periods = RepayPeriodsEnum.randomValue();
        record.setRepayPeriod(periods);
        record.setGracePeriod(1 + (periods % 9) / 3);//宽松期最多三天
        record.setOverdueRate(periods / (3 * 100.0));//罚息

        int phc = req.getProductCode().hashCode();
        int customerRate = 30 + (phc % 9) + periods / 3;//每个产品的对客利率应该一样
        int fundRate = 6 + (phc % 3);//资金方
        int propertyRate = 12 + (phc % 6);//资产方
        int guarantorRate = customerRate - fundRate - propertyRate;//担保方

        record.setCustomerRate(customerRate / 100.0);
        record.setPropertyRate(propertyRate / 100.0);
        record.setFundRate(fundRate / 100.0);
        record.setGuarantorRate(guarantorRate / 100.0);

        record.setStatus(0);
        record.setCreateTime(new Date());
        int insert = loanInfoMapper.insert(record);
        return insert;
    }

    // 已处理的订单
    private long loan_info_id = -1;

    //生产还款记录
    //queryWrapper.lt（）——小于
    //queryWrapper.le（）——小于等于
    @Override
    public Object genLoanAndPlan() {
        Map<String, Object> reMap = new HashMap<>();
        LambdaQueryWrapper<LoanInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LoanInfo::getStatus, 0);
        queryWrapper.gt(LoanInfo::getId, loan_info_id);
        queryWrapper.orderByAsc(LoanInfo::getId); //从小到大排序
        queryWrapper.last("limit 9");
        List<LoanInfo> list = loanInfoMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            log.info("暂无放款申请需要处理");
        } else {
            int successCount = 0;
            int failureCount = 0;
            for (LoanInfo item : list) {
                int status = dealOneLoanInfo(item);
                if (status > 0) {
                    successCount++;
                } else {
                    failureCount++;
                }
            }
            reMap.put("successCount", successCount);
            reMap.put("failureCount", failureCount);
        }

        return reMap;
    }

    private int dealOneLoanInfo(LoanInfo item) {
        int re = 0;
        try {
            String dueBillNo = System.currentTimeMillis() + "";
            //模拟放款
            LoanInfo loan = new LoanInfo();
            loan.setId(item.getId());
            loan.setStatus(1);
            loan.setDueBillNo(dueBillNo);
            loan.setFundCode(BankCardUtil.getBankCode(item.getBankCard()));
            int status = loanInfoMapper.updateById(loan);
            if (status > 0) {
                log.info("放款成功,用户={},金额={}", item.getName(), item.getLoanAmount());
            } else {
                log.info("放款失败,用户={} ", item.getName());
            }

            //生成还款计划
            List<RepaymentPlan> repaymentPlanList = new LinkedList<>();
            Integer repayPeriod = item.getRepayPeriod();

            //计算每月还款本金和利息
            Map<Integer, Double[]> repayMap = null;
            if (RepayMethodEnum.AMOUNT.value == item.getRepayMethod()) {
                //等额本金
                repayMap = RateUtil.listEqualPrincipalAmount(item.getLoanAmount(), item.getCustomerRate(), repayPeriod);
            } else if (RepayMethodEnum.INTEREST.value == item.getRepayMethod()) {
                //等额本息
                repayMap = RateUtil.listEqualPrincipalInterest(item.getLoanAmount(), item.getCustomerRate(), repayPeriod);
            } else {
                throw new RuntimeException("还款方式不支持");
            }

            String bankCode = BankCardUtil.getBankCode(item.getBankCard());
            int bc2 = bankCode.hashCode() % 2;
            //Date oneMonthDateBegin = DateUtil.getMonthBegin();//默认是当前时间
            Date oneMonthDateBegin = DateUtil.addMonth(DateUtil.getMonthBegin(), 0 - RandomUtil.getRandom(repayPeriod));//假定一个开始时间
            Date billDate = DateUtil.addDay(oneMonthDateBegin, 5 + bc2);
            Date repayDate = DateUtil.addDay(oneMonthDateBegin, 20 + 5 * bc2);
            Date overDuwDate = DateUtil.addDay(oneMonthDateBegin, 20 + 5 * bc2 + item.getGracePeriod());

            for (int i = 1; i <= repayPeriod; i++) {
                RepaymentPlan plan = new RepaymentPlan();

                //还款额
                Double[] piArr = repayMap.get(i);
                plan.setRepayPrincipal(piArr[1]);
                plan.setRepayInterest(piArr[2]);
                plan.setRemainingAmount(piArr[3]);
                plan.setOverdueInterest(0.0);
                plan.setRepayTotal(plan.getRepayPrincipal() + plan.getRepayInterest() + plan.getOverdueInterest());

                //还款时间
                plan.setBillTime(DateUtil.addMonth(billDate, i));
                plan.setRepayTime(DateUtil.addMonth(repayDate, i));
                plan.setOverdueTime(DateUtil.addMonth(overDuwDate, i));

                plan.setName(item.getName());
                plan.setIdCard(item.getIdCard());
                plan.setProductCode(item.getProductCode());
                plan.setPhoneNo(item.getPhoneNo());
                plan.setBankCard(item.getBankCard());
                plan.setOverdueRate(item.getOverdueRate());//逾期利率
                plan.setBankCode(bankCode);
                plan.setSessionId(item.getSessionId());
                plan.setUserId(item.getUserId());
                plan.setTerm(i);
                plan.setRepayStatus(RepayPlanEnum.UN_PAY.value);//未还款---下面更新
//                plan.setOverdueStatus(0);//未逾期---下面更新
                plan.setDueBillNo(dueBillNo);
                plan.setCreateTime(new Date());
                repaymentPlanList.add(plan);
            }

            if (repaymentPlanList.size() > 0) {
                repaymentPlanService.saveBatch(repaymentPlanList);
                log.info("还款计划生产成功,sessionId={}", item.getSessionId());
            } else {
                log.info("还款计划生产失败,sessionId={}", item.getSessionId());
            }

            //模拟插入还款记录
            if (repaymentPlanList.size() > 0) {
                List<RepaymentPlan> planStatusList = new LinkedList<>();
                List<RepaymentRecord> repaymentRecordList = new LinkedList<>();
                Date nowDate = new Date();
                for (RepaymentPlan plan : repaymentPlanList) {
                    Integer differMonth = DateUtil.differMonth(nowDate, plan.getBillTime());
                    if (differMonth > 0) {
                        //配置还款记录
                        RepaymentRecord record = getRepaymentRecordByPlan(plan);
                        Date payTime = record.getPayTime();
                        repaymentRecordList.add(record);

                        //配置还款计划的状态
                        {
                            RepaymentPlan planStatus = new RepaymentPlan();
                            planStatus.setId(plan.getId());
                            planStatus.setPayTime(payTime);//还款时间
                            Integer overdueDay = DateUtil.differDay(payTime, plan.getOverdueTime());//逾期天数,负值则是提前还款
                            planStatus.setOverdueDay(overdueDay);
                            planStatus.setOverdueStatus(overdueDay > 0 ? OverdueStatusEnum.OVERDUE.value : OverdueStatusEnum.UN_OVERDUE.value);
                            planStatus.setRepayStatus(RepayPlanEnum.PAY.value);
                            planStatusList.add(planStatus);
                        }

                        //结清时补充的记录
                        if (record.getStatus() == RepayStatusEnum.PAY_All.value
                                || record.getStatus() == RepayStatusEnum.PAY_All.value) {
                            //赛选出剩余记录
                            LambdaQueryWrapper<RepaymentPlan> queryWrapper1 = new LambdaQueryWrapper<>();
                            queryWrapper1.eq(RepaymentPlan::getDueBillNo, plan.getDueBillNo());
                            queryWrapper1.gt(RepaymentPlan::getTerm, plan.getTerm());
                            queryWrapper1.orderByAsc(RepaymentPlan::getTerm);
                            List<RepaymentPlan> remPlans = repaymentRlanMapper.selectList(queryWrapper1);
                            for (RepaymentPlan remPlan : remPlans) {
                                RepaymentPlan remPlanStatus = new RepaymentPlan();
                                remPlanStatus.setId(remPlan.getId());
                                remPlanStatus.setPayTime(payTime);
                                remPlanStatus.setRepayStatus(RepayPlanEnum.PAY.value);
                                Integer remOverdueDay = DateUtil.differDay(payTime, remPlan.getOverdueTime());
                                remPlanStatus.setOverdueDay(remOverdueDay);
                                remPlanStatus.setOverdueStatus(remOverdueDay > 0 ? OverdueStatusEnum.OVERDUE.value : OverdueStatusEnum.UN_OVERDUE.value);
                                planStatusList.add(remPlanStatus);
                            }
                        }
                    }
                }

                //还款记录
                if (repaymentRecordList.size() > 0) {
                    iRepaymentRecordService.saveBatch(repaymentRecordList);
                    log.info("还款记录-生产成功,sessionId={}", item.getSessionId());
                }

                //还款计划状态更新
                if (planStatusList.size() > 0) {
                    repaymentPlanService.updateBatchById(planStatusList);
                    log.info("更新还款计划状态-生产成功,sessionId={}", item.getSessionId());
                }
            }

            re = 1;
            loan_info_id = item.getId();
        } catch (Exception e) {
            log.error("模拟放款和还款计划失败,用户={},sessionId={}", item.getName(), item.getSessionId(), e);
        }
        return re;
    }


    //根据还款计划  生成一条还款记录
    @Override
    public RepaymentRecord getRepaymentRecordByPlan(RepaymentPlan plan) {
        RepaymentRecord record = new RepaymentRecord();
        record.setBankCard(plan.getBankCard());
        record.setBankCode(plan.getBankCode());
        record.setName(plan.getName());
        record.setDueBillNo(plan.getDueBillNo());
        record.setSessionId(plan.getSessionId());
        record.setCreateTime(new Date());
        record.setTerm(plan.getTerm());
        record.setUserId(plan.getUserId());

        Date monthBegin = DateUtil.getMonthBegin(plan.getOverdueTime());
        Date monthEnd = DateUtil.getMonthEnd(plan.getOverdueTime());
        int day = DateUtil.dayOfMonth(monthEnd);
        Date payTime = DateUtil.addDay(monthBegin, RandomUtil.getRandom(day));//随机一个还款时间
        record.setPayTime(payTime);
        Integer random100 = RandomUtil.getRandom(100);
        if (plan.getOverdueTime().compareTo(payTime) >= 0) {
            if (random100 >= 5) {
                record.setStatus(RepayStatusEnum.PAY.getValue());//提前还款   (,逾期日前】
                record.setRepayAmount(plan.getRepayTotal());
            } else {
                record.setStatus(RepayStatusEnum.PAY_All.getValue());//提前还款   一次性结清
                record.setRepayAmount(plan.getRepayTotal() + plan.getRemainingAmount());
            }
        } else {
            if (random100 >= 30) {
                record.setStatus(RepayStatusEnum.OVER_PAY.getValue());//逾期还款  (逾期日前,）
                record.setRepayAmount(plan.getRepayTotal() + plan.getRemainingAmount());
            } else {
                record.setStatus(RepayStatusEnum.OVER_PAY_All.getValue());//逾期还款   一次性结清
                record.setRepayAmount(plan.getRepayTotal() + plan.getRemainingAmount());
            }
        }
        return record;
    }

    @Override
    public Page<LoanInfo> pageList(LoanRecordPageReq req) {
        PageHelper.startPage(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<LoanInfo> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(req.getName())) {
            queryWrapper.like(LoanInfo::getName, req.getName());
        }
        if (StringUtils.isNotBlank(req.getSessionId())) {
            queryWrapper.like(LoanInfo::getSessionId, req.getSessionId());
        }
        if (StringUtils.isNotBlank(req.getIdCard())) {
            queryWrapper.like(LoanInfo::getIdCard, req.getIdCard());
        }
        if (StringUtils.isNotBlank(req.getBankCard())) {
            queryWrapper.like(LoanInfo::getBankCard, req.getBankCard());
        }
        if (StringUtils.isNotBlank(req.getProductCode())) {
            queryWrapper.like(LoanInfo::getProductCode, req.getProductCode());
        }

        queryWrapper.orderByDesc(LoanInfo::getId);
        List<LoanInfo> list = loanInfoMapper.selectList(queryWrapper);
        return new Page<>(list, new PageInfo<>(list).getTotal(), req);
    }
}
